/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package regulatoryNetworks;

import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.parsers.SimilarityFileParser;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.units.Gene;
import functionalEnrichment.semanticSimilarity.semanticSimilarityCalculator.units.SemanticSimilarity;
import humanNetwork.HumanPPINetwork;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import units.CellType;
import units.MonkeyType;
import utils.FileUtils;
import utils.Handle;

/**
 *
 * @author jamie
 */
public class RegulatoryNetwork {

    private double miThreshold = 0.3;
    private File outputFolder = new File("/Users/jamie/Dropbox/monkeys/networks/regulatoryNetworks/");
    private File inputFolder = new File("/Users/jamie/Dropbox/monkeys/outputForR/minet/");
    private Handle handle = Handle.getConnectedHandle("monkeys");
    private HumanPPINetwork humanNetwork = new HumanPPINetwork(HumanPPINetwork.ALL);
    private SimilarityFileParser sfp = new SimilarityFileParser();
    private File similaritiesFile = new File("/Users/jamie/Documents/monkeys/geneSimilarities/similarities_P.txt");
    private ArrayList<String> probeIds;
    private ArrayList<String> hivProts;
    private HashMap<String, List<String>> hivInteractions;
    private int toCutoff = 0;

    public RegulatoryNetwork() {
        try {
            sfp.readAllSimilarities(similaritiesFile);
        } catch (IOException ex) {
            Logger.getLogger(RegulatoryNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void outputAllNetworks() {
        for (MonkeyType mt : MonkeyType.values()) {
            for (CellType ct : CellType.values()) {
                outputNetwork(mt, ct);
            }
        }
    }

    public void outputNetwork(MonkeyType mt, CellType ct) {
        String source = mt.name() + ct.name();

        File inputFile = new File(inputFolder, source + "_select_results.txt");
        Map<String, Double> resultsMap = null;
        try {
            resultsMap = getResultsFromFile(inputFile);
        } catch (IOException ex) {
            Logger.getLogger(RegulatoryNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            runEdgeOutput(resultsMap, source);

        } catch (IOException ex) {
            Logger.getLogger(RegulatoryNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            runNodeOutput(source);
        } catch (IOException ex) {
            Logger.getLogger(RegulatoryNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private Map<String, Double> getResultsFromFile(File inputFile) throws IOException {

        Map<String, Double> results = new TreeMap<String, Double>();
        BufferedReader reader = FileUtils.getBufferedReader(inputFile);
        String line;
        boolean first = true;
        probeIds = new ArrayList<String>();
        hivProts = new ArrayList<String>();
        hivInteractions = new HashMap<String, List<String>>();
        while ((line = reader.readLine()) != null) {
            String[] split = line.split("\t");
            if (first) {

                for (String s : split) {
                    String id = s.substring(1);
                    probeIds.add(id);
                    List<String> hivInts = getHivInteractions(id);
                    if (hivInts.size() > 0) {
                        hivInteractions.put(id, hivInts);
                        for (String hivProt : hivInts) {
                            if (!hivProts.contains(hivProt)) {
                                hivProts.add(hivProt);
                            }
                        }
                    }
                }
                first = false;
            } else {
                String probeId_1 = split[0].substring(1);

                for (int i = 1; i < split.length; i++) {
                    double mi = Double.parseDouble(split[i]);
                    if (mi >= miThreshold) {
                        String probeId_2 = probeIds.get(i - 1);
                        String[] ids = {probeId_1, probeId_2};
                        Arrays.sort(ids);
                        String key = ids[0] + ":" + ids[1];


                        results.put(key, mi);
                    }
                }
            }
        }
        reader.close();
        return results;

    }

    private void runEdgeOutput(Map<String, Double> resultsMap, String source) throws IOException {
        BufferedWriter writer = FileUtils.getBufferedWriter(new File(outputFolder, source + "_edges.txt"));
        try {
            writer.append("id_1\tid_2\tMI\tppi\ttermOverlap\tsource\n");
        } catch (IOException ex) {
            Logger.getLogger(RegulatoryNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
        HashSet<String> added = new HashSet<String>();
        for (String key : resultsMap.keySet()) {
            String[] pIds = key.split(":");
            List<Integer> gIds_1 = getGeneIds(pIds[0]);
            List<Integer> gIds_2 = getGeneIds(pIds[1]);
            boolean ppi = hasPPI(gIds_1, gIds_2);
            List<String> swissIds_1 = getSwissIds(pIds[0]);
            List<String> swissIds_2 = getSwissIds(pIds[1]);
            int termOverlap = getTermOverlap(swissIds_1, swissIds_2);
            if (termOverlap >= toCutoff) {
                writer.append(pIds[0] + "\t" + pIds[1] + "\t" + resultsMap.get(key) + "\t" + ppi + "\t" + termOverlap + "\thuman\n");
                if (!added.contains(pIds[0])) {
                    added.add(pIds[0]);
                }
                if (!added.contains(pIds[1])) {
                    added.add(pIds[1]);
                }
            }
        }
        for (String key : hivInteractions.keySet()) {
            if (added.contains(key)) {
                for (String hivProt : hivInteractions.get(key)) {
                    writer.append(key + "\t" + hivProt + "\t" + 1 + "\ttrue\t" + 17 + "\thivHuman\n");
                }
            }
        }
        writer.close();
    }

    private void runNodeOutput(String source) throws IOException {
        BufferedWriter writer = FileUtils.getBufferedWriter(new File(outputFolder, source + "_nodes.txt"));
        writer.append("id\tcluster\tsymbol\torganism\n");
        for (String probeId : probeIds) {
            writer.append(probeId + "\t" + getClusterId(probeId, source) + "\t" + getSymbol(probeId) + "\thuman\n");
        }
        for (String hp : hivProts) {
            writer.append(hp + "\t-1\t" + hp + "\thiv\n");
        }

        writer.close();

    }

    private List<Integer> getGeneIds(String probeIdString) {
        String sql = "select distinct gId from probeIdLookup where probeId=" + probeIdString;
        List<Integer> gIds = new ArrayList<Integer>();
        ResultSet rs = handle.runSQLquery(sql);
        try {
            while (rs.next()) {
                int gId = rs.getInt("gId");
                gIds.add(gId);
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(RegulatoryNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
        if (gIds.size() > 1) {
            System.out.println("probe had more than one gene: " + probeIdString);
        }
        return gIds;
    }

    private List<String> getSwissIds(String probeIdString) {
        String sql = "select distinct swissProtAccession from probeIdLookup t1, swissProtLookup t2 where t1.gId=t2.gId and t1.probeId=" + probeIdString;
        List<String> swissIds = new ArrayList<String>();
        ResultSet rs = handle.runSQLquery(sql);
        try {
            while (rs.next()) {
                String probeId = rs.getString("swissProtAccession");
                swissIds.add(probeId);
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(RegulatoryNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
        return swissIds;
    }

    private boolean hasPPI(List<Integer> gIds_1, List<Integer> gIds_2) {
        for (int gId_1 : gIds_1) {
            for (int gId_2 : gIds_2) {
                int[] ids = {gId_1, gId_2};
                Arrays.sort(ids);
                String key = ids[0] + ":" + ids[1];
                if (humanNetwork.getEdgeHash().containsKey(key)) {
                    return true;
                }
            }
        }
        return false;
    }

    private int getTermOverlap(List<String> swissIds_1, List<String> swissIds_2) {
        int max = 0;
        for (String id_1 : swissIds_1) {
            for (String id_2 : swissIds_2) {
                String[] ids = {id_1, id_2};
                Arrays.sort(ids);
                Gene g1 = new Gene(ids[0]);
                Gene g2 = new Gene(ids[1]);
                int hashcode = new SemanticSimilarity(g1, g2).hashCode();
                if (sfp.getSimilarityHash().containsKey(hashcode)) {
                    SemanticSimilarity ss = (SemanticSimilarity) sfp.getSimilarityHash().get(hashcode);
                    if (ss.getSimilarity() > max) {
                        max = ss.getSimilarity();
                    }
                }
            }
        }
        return max;
    }

    private int getClusterId(String probeId, String source) {
        String sql = "select clusterId from clustermembership where probeId=" + probeId + " and monkeytype = '" + source.substring(0, 1) + "' and cellType = '" + source.substring(1, 2) + "'";
        ResultSet rs = handle.runSQLquery(sql);
        int clusterId = 0;
        try {
            if (rs.next()) {
                clusterId = rs.getInt("clusterId");
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(RegulatoryNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
        return clusterId;

    }

    private String getSymbol(String probeId) {
        String sql = "select symbol from ncbi.gene_info t1, probeIdLookup t2 where t1.gId=t2.gId and t2.probeId=" + probeId;
        ResultSet rs = handle.runSQLquery(sql);
        String symbol = probeId;
        try {
            if (rs.next()) {
                symbol = rs.getString("symbol");
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(RegulatoryNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
        return symbol;

    }

    private List<String> getHivInteractions(String id) {
        String sql = "select distinct name_1 from hiv_interactions.hiv_interactions t1, probeIdLookup t2 where (t1.interaction = 'regulates' || t1.interaction = 'upregulates' || t1.interaction = 'downregulates') and t2.gId=t1.gId_2 and t2.probeId=" + id;
        ResultSet rs = handle.runSQLquery(sql);
        List<String> interactions = new ArrayList<String>();
        try {
            while (rs.next()) {
                interactions.add(rs.getString("name_1"));
            }
            rs.close();
        } catch (SQLException ex) {
            Logger.getLogger(RegulatoryNetwork.class.getName()).log(Level.SEVERE, null, ex);
        }
        return interactions;
    }
}
